package com.meme.editor.gui.sprite2d;

import com.meme.editor.event.EntityChangedEvent;
import com.meme.editor.model.sprite2d.Module;
import com.meme.editor.model.sprite2d.Tiled2dGrid;
import com.meme.editor.model.sprite2d.Tiled2dLayer;
import com.meme.editor.model.sprite2d.Tiled2dLayerCell;
import com.meme.editor.model.sprite2d.Tiled2dPalette;
import com.meme.editor.model.sprite2d.Tiled2dBackground;

import java.awt.Color;
import java.awt.Graphics;

public class Tiled2dGridSelectedRegion 
{
	public int mLeft;
	public int mTop;
	public int mRight;
	public int mBottom;
	
	
	public void setRegion (int row1, int col1, int row2, int col2)
	{
		mTop = row1;
		mBottom = row2;
		mLeft = col1;
		mRight = col2;
	}
	
	int getRows ()
	{
		return mBottom - mTop + 1;
	}
	
	int getCols ()
	{
		return mRight - mLeft + 1;
	}
	
	public void makeRegionValid (Tiled2dGrid tiled2dGrid)
	{
		makeRegionValid (tiled2dGrid.getCellRows() - 1, tiled2dGrid.getCellCols() - 1);
	}
	
	public void makeRegionValid (int maxRow, int maxCol)
	{
		if ( mLeft < 0 ) mLeft = 0;
		if ( mLeft > maxCol ) mLeft = maxCol;
		if ( mRight < 0 ) mRight = 0;
		if ( mRight > maxCol ) mRight = maxCol;
		if ( mLeft > mRight )
		{
			int t = mLeft;
			mLeft = mRight;
			mRight = t;
		}
		
		if ( mTop < 0 ) mTop = 0;
		if ( mTop > maxRow ) mTop = maxRow;
		if ( mBottom < 0 ) mBottom = 0;
		if ( mBottom > maxRow ) mBottom = maxRow;
		if ( mTop > mBottom )
		{
			int t = mTop;
			mTop = mBottom;
			mBottom = t;
		}
	}
	
	

	
	
	public Tiled2dBackground createTiled2dBackgroundFromGridSelectionRegion (Tiled2dGrid tiled2dGrid)
	{
		makeRegionValid (tiled2dGrid);
		
		if ( tiled2dGrid instanceof Tiled2dPalette )
		{
			Tiled2dPalette tilePalette = (Tiled2dPalette) tiled2dGrid;
			
			Tiled2dBackground background = new Tiled2dBackground (tilePalette.getCellWidth(), tilePalette.getCellHeight(), getRows (), getCols () );
			
			// copy
			Tiled2dLayer layer = background.getLayerByIndex (0);
			int index = 0;
			for (int row = mTop; row <= mBottom; ++ row)
			{
				for (int col = mLeft; col <= mRight; ++ col)
				{
					Tiled2dLayerCell layerCell = layer.getLayerCellByIndex (index ++);
					layerCell.setModule ( tilePalette.getTiled2dModuleByPos(row, col) );
				}
			}
			
			return background;
		}
		
		if ( tiled2dGrid instanceof Tiled2dBackground )
		{
			Tiled2dBackground sourceBackground = (Tiled2dBackground) tiled2dGrid;
			
			Tiled2dBackground destBackground = new Tiled2dBackground (sourceBackground.getCellWidth(), sourceBackground.getCellHeight(), getRows (), getCols () );
			for (int layerID = 0; layerID < sourceBackground.getLayersCount(); ++ layerID )
			{
				Tiled2dLayer sourceLayer = sourceBackground.getLayerByIndex(layerID);
				Tiled2dLayerStatus layerStatus = Tiled2dLayerListCellRenderer.getTiled2dLayerStatus ( sourceLayer );
				
				if (layerID > 0)
					destBackground.addNewChild();
				
				Tiled2dLayer destLayer = destBackground.getLayerByIndex (layerID);
				destLayer.setUserObject (layerStatus);
			}
			
			// copy
			copyTiled2dBackground (
					sourceBackground, mTop, mLeft,
					destBackground, 0, 0, 
					getRows(), getCols(), false, false, true);
			
			return destBackground;
		}

		return null;
	}
	
	public static void copyTiled2dBackground (Tiled2dBackground sourceBackground, Tiled2dBackground destBackground, int startRow, int startCol)
	{
		copyTiled2dBackground (
				sourceBackground, 0, 0, 
				destBackground, startRow, startCol, 
				sourceBackground.getCellRows(), sourceBackground.getCellCols(), false, false, false);
	}
	
//	public static int getVisibleTiled2dLayers (Tiled2dBackground background)
//	{
//		int count = 0;
//		for (int layerID = 0; layerID < background.getLayersCount(); ++ layerID )
//		{
//			Tiled2dLayer sourceLayer = background.getLayerByIndex(layerID);
//			Tiled2dLayerStatus layerStatus = Tiled2dLayerListCellRenderer.getTiled2dLayerStatus ( sourceLayer );
//			if (layerStatus.isVisible())
//				++ count;
//		}
//		
//		return count;
//	}
	
	static Tiled2dLayer getToppestUnlockedTiled2dLayer (Tiled2dBackground background)
	{
		int lastID = 0;
		for (int layerID = 0; layerID < background.getLayersCount(); ++ layerID )
		{
			Tiled2dLayer layer = background.getLayerByIndex(layerID);
			Tiled2dLayerStatus layerStatus = Tiled2dLayerListCellRenderer.getTiled2dLayerStatus ( layer );
			if (! layerStatus.isLocked())
				lastID = layerID;
		}
		
		return background.getLayerByIndex (lastID);
	}
	
	static Tiled2dLayer getTiled2dLayerByUserObject (Tiled2dBackground background, Object userObject)
	{
		for (int layerID = 0; layerID < background.getLayersCount(); ++ layerID )
		{
			Tiled2dLayer layer = background.getLayerByIndex(layerID);
			if (layer.getUserObject() == userObject)
				return layer;
		}
		
		return null;
	}
	
	public static void copyTiled2dBackground (
			Tiled2dBackground sourceBackground, int sourceStartRow, int sourceStartCol, 
			Tiled2dBackground destBackground, int destStartRow, int destStartCol, 
			int rows, int cols, boolean flipX, boolean flipY, boolean alwaysCopy)
	{
		if (sourceBackground.getLayersCount() == 0 || destBackground.getLayersCount() == 0)
			return;

		if (sourceBackground.getLayersCount() == 1)
		{
			copyTiled2dLayer (
					sourceBackground.getLayerByIndex(0), sourceStartRow, sourceStartCol,
					getToppestUnlockedTiled2dLayer (destBackground), destStartRow, destStartCol,
					rows, cols, flipX, flipY
					);
			
			return;
		}
		
		for (int layerID = 0; layerID < sourceBackground.getLayersCount(); ++ layerID)
		{
			Tiled2dLayer sourceLayer = sourceBackground.getLayerByIndex(layerID);
			Tiled2dLayerStatus layerStatus = Tiled2dLayerListCellRenderer.getTiled2dLayerStatus ( sourceLayer );

			if ( layerStatus.isLocked() && !alwaysCopy)
				continue;
			
			Tiled2dLayer destLayer = getTiled2dLayerByUserObject (destBackground, layerStatus);
			if (destLayer == null)
				continue;
			
			copyTiled2dLayer (
					sourceLayer, sourceStartRow, sourceStartCol,
					destLayer, destStartRow, destStartCol,
					rows, cols, flipX, flipY
					);

		}
	}

	static void copyTiled2dLayer (
			Tiled2dLayer sourceTiled2dLayer, int sourceStartRow, int sourceStartCol, 
			Tiled2dLayer destTiled2dLayer, int destStartRow, int destStartCol, 
			int rows, int cols, boolean flipX, boolean flipY )
	{
		if (destStartRow + rows > destTiled2dLayer.getCellRows())
			rows -= destStartRow + rows - destTiled2dLayer.getCellRows();
		if (destStartRow < 0)
		{
			sourceStartRow -= destStartRow;
			rows += destStartRow;
			destStartRow = 0;
		}
		
		if (destStartCol + cols > destTiled2dLayer.getCellCols())
			cols -= destStartCol + cols - destTiled2dLayer.getCellCols();
		if (destStartCol < 0)
		{
			sourceStartCol -= destStartCol;
			cols += destStartCol;
			destStartCol = 0;
		}
		
		// assert source values
		// ...
		
		// copy
		for (int row = 0; row < rows; ++ row)
		{
			for (int col = 0; col < cols; ++ col)
			{
				int sourceRow = sourceStartRow + row;
				int sourceCol = sourceStartCol + col;
				int destRow = destStartRow + row;
				int destCol = destStartCol + col;
				
				Tiled2dLayerCell sourceLayerCell = sourceTiled2dLayer.getLayerCellByPos (sourceRow, sourceCol);
				Tiled2dLayerCell destLayerCell   = destTiled2dLayer.getLayerCellByPos (destRow, destCol);
				destLayerCell.setModule ( sourceLayerCell.getModule() );
				destLayerCell.setFlipX ( sourceLayerCell.isFlipX() );
				destLayerCell.setFlipY ( sourceLayerCell.isFlipY() );
				destLayerCell.setPaletteID ( sourceLayerCell.getPaletteID() );
			}
		}
		
		if (rows > 0 && cols > 0)
		{
			destTiled2dLayer.notifyModified (EntityChangedEvent.ModType_General);
		}
	}
	
	public void xFlipTiled2dBackground (Tiled2dBackground background)
	{
		flipTiled2dBackground (background, mTop, mLeft, getRows (), getCols (), true, false, false);
	}
	
	public void yFlipTiled2dBackground (Tiled2dBackground background)
	{
		flipTiled2dBackground (background, mTop, mLeft, getRows (), getCols (), false, true, false);
	}
	
	public static void xFlipTiled2dBackgroundWholly (Tiled2dBackground background)
	{
		flipTiled2dBackground (background, 0, 0, background.getCellRows(), background.getCellCols(), true, false, false );
	}
	
	public static void yFlipTiled2dBackgroundWholly (Tiled2dBackground background)
	{
		flipTiled2dBackground (background, 0, 0, background.getCellRows(), background.getCellCols(), false, true, false );
	}
	
	public static void flipTiled2dBackground (Tiled2dBackground background, int startRow, int startCol, int rows, int cols, boolean flipX, boolean flipY, boolean alwaysFlip)
	{
		for (int layerID = 0; layerID < background.getLayersCount(); ++ layerID)
		{
			Tiled2dLayer layer = background.getLayerByIndex(layerID);
			Tiled2dLayerStatus layerStatus = Tiled2dLayerListCellRenderer.getTiled2dLayerStatus ( layer );

			if ( layerStatus.isLocked() && !alwaysFlip)
				continue;
			
			flipTiled2dLayer (layer, startRow, startCol, rows, cols, flipX, flipY);
		}

	}
	
	static void flipTiled2dLayer (Tiled2dLayer layer, int topRow, int leftCol, int rows, int cols, boolean flipX, boolean flipY)
	{
		int bottomRow = topRow + rows - 1;
		int rightCol = leftCol + cols - 1;


		if (flipX)
		{
			for (int row = topRow; row <= bottomRow; ++ row)
			{
				int col1 = leftCol;
				int col2 = rightCol;
				
				while (col1 <= col2)
				{
					Tiled2dLayerCell layerCell1 = layer.getLayerCellByPos (row, col1);
					Tiled2dLayerCell layerCell2 = layer.getLayerCellByPos (row, col2);
					
					if (col1 != col2)
					{
						exchangeLayerCellData (layerCell1, layerCell2);
						layerCell1.setFlipX (!layerCell1.isFlipX());
					}
					
					layerCell2.setFlipX (!layerCell2.isFlipX());
					
					++ col1;
					-- col2;
				}
			}
		}
		
		if (flipY)
		{
			for (int col = leftCol; col <= rightCol; ++ col)
			{
				int row1 = topRow;
				int row2 = bottomRow;
				
				while (row1 <= row2)
				{
					Tiled2dLayerCell layerCell1 = layer.getLayerCellByPos (row1, col);
					Tiled2dLayerCell layerCell2 = layer.getLayerCellByPos (row2, col);
					
					if (row1 != row2)
					{
						exchangeLayerCellData (layerCell1, layerCell2);
						layerCell1.setFlipY (!layerCell1.isFlipY());
					}
					
					layerCell2.setFlipY (!layerCell2.isFlipY());
					
					++ row1;
					-- row2;
				}
			}
		}

	}
	
	static void exchangeLayerCellData (Tiled2dLayerCell layerCell1, Tiled2dLayerCell layerCell2)
	{
		Module module1 = layerCell1.getModule();
		Module module2 = layerCell2.getModule();
		layerCell1.setModule(module2);
		layerCell2.setModule(module1);
		
		int paletteID1 = layerCell1.getPaletteID();
		int paletteID2 = layerCell2.getPaletteID();
		layerCell1.setPaletteID(paletteID2);
		layerCell2.setPaletteID(paletteID1);
		
		boolean flipX1 = layerCell1.isFlipX();
		boolean flipX2 = layerCell2.isFlipX();
		layerCell1.setFlipX(flipX2);
		layerCell2.setFlipX(flipX1);
		
		boolean flipY1 = layerCell1.isFlipY();
		boolean flipY2 = layerCell2.isFlipY();
		layerCell1.setFlipY(flipY2);
		layerCell2.setFlipY(flipY1);

	}
	
	
	public void clearTiled2dBackground (Tiled2dBackground background)
	{
		makeRegionValid (background);
	
		clearTiled2dBackground (background, mTop, mLeft, getRows (), getCols (), false );
	}
	
//	public static void clearTiled2dBackgroundWholly (Tiled2dBackground background)
//	{
//		clearTiled2dBackground (background, 0, 0, background.getCellRows(), background.getCellCols(), );
//	}
	
	public static void clearTiled2dBackground (Tiled2dBackground background, int topRow, int leftCol, int rows, int cols, boolean awaysClear)
	{
		for (int layerID = 0; layerID < background.getLayersCount(); ++ layerID)
		{
			Tiled2dLayer layer = background.getLayerByIndex(layerID);
			Tiled2dLayerStatus layerStatus = Tiled2dLayerListCellRenderer.getTiled2dLayerStatus ( layer );

			if ( layerStatus.isLocked() && !awaysClear)
				continue;
			
			clearTiled2dLayer (layer, topRow, leftCol, rows, cols);
		}
	}
	
	static void clearTiled2dLayer (Tiled2dLayer layer, int topRow, int leftCol, int rows, int cols)
	{
		int bottomRow = topRow + rows;
		int rightCol = leftCol + cols;
		for (int row = topRow; row < bottomRow; ++ row)
		{
			for (int col = leftCol; col < rightCol; ++ col)
			{
				Tiled2dLayerCell layerCell   = layer.getLayerCellByPos (row, col);
				layerCell.setModule ( null );
				layerCell.setFlipX(false);
				layerCell.setFlipY(false);
				layerCell.setPaletteID(0);
			}
		}

	}
}
